// IteratorCommon.h: interface for the IteratorCommon class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_ITERATORCOMMON_H__FBB43028_A5D2_4DA2_9374_1926BC49796C__INCLUDED_)
#define AFX_ITERATORCOMMON_H__FBB43028_A5D2_4DA2_9374_1926BC49796C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <assert.h>
#include "SmallObject.h"

template<class WrappedObjectClass,class FlagClass=int>
class Wrapper
{
public:
	Wrapper() {}
	Wrapper( const WrappedObjectClass& obj ) : m_obj( obj ) {}
	Wrapper( const WrappedObjectClass& obj, const FlagClass& flag ) : m_obj( obj ), m_flag( flag ) {}
	Wrapper( const Wrapper& wrapper ) : m_obj( wrapper.m_obj ), m_flag( wrapper.m_flag ) {}
	Wrapper& operator=( const Wrapper& wrapper ) { 
		m_obj = wrapper.m_obj; m_flag = wrapper.m_flag; return *this; }

public:
	bool operator==( const Wrapper& wrapper ) const {
		return m_flag == wrapper.m_flag && m_obj == wrapper.m_obj; }
	bool operator !=( const Wrapper& wrapper ) const {
		return !( operator==( wrapper ) ); }
	operator WrappedObjectClass&() { return m_obj; }
	operator const WrappedObjectClass&() const { return m_obj; }

public:
	WrappedObjectClass& WrappedObject() { return m_obj; }
	const WrappedObjectClass& WrappedObject() const { return m_obj; }
	void WrappedObject( const WrappedObjectClass& obj ) { m_obj = obj; }
	FlagClass& Flag() { return m_flag; }
	const FlagClass& Flag() const { return m_flag; }
	void Flag( const FlagClass& flag ) { m_flag = flag; }

private:
	WrappedObjectClass m_obj;
	FlagClass m_flag;
};

template<class SharedObjectClass>
class Shareware : public SmallObject
{
public:
	Shareware() : m_refCnt( 0 ) {}
	Shareware( const SharedObjectClass& obj ) : m_obj( obj ), m_refCnt( 0 ) {}
	Shareware( const Shareware& ware ) : m_obj( ware.m_obj ), m_refCnt( 0 ) {}
	Shareware& operator= ( const Shareware& ware ) { if ( &ware != this ) m_obj = ware.m_obj; return *this; }
	
public:
	const SharedObjectClass& SharedObject() const { return m_obj; }
	SharedObjectClass& SharedObject() { return m_obj; }
	void SharedObject( const SharedObjectClass& obj ) { m_obj = obj; }
	
	long RefCount() const { return m_refCnt; }
	void IncRef() { InterlockedIncrement(&m_refCnt); }
	void DecRef() { InterlockedDecrement(&m_refCnt); }
	
private:
	SharedObjectClass m_obj;
	long m_refCnt;
};

template<class SharedObjectClass>
class SharewarePtr
{
public:
	typedef Shareware<SharedObjectClass> WareType;
	SharewarePtr() : m_ptr( 0 ) {}
	SharewarePtr( const SharedObjectClass& obj ) { m_ptr = new WareType( obj ); IncRef(); }
	SharewarePtr( const SharewarePtr& ware ) : m_ptr( ware.m_ptr ) { IncRef(); }
	~SharewarePtr() { DecRef(); }

public:
	void CreateInstance() { if ( m_ptr ) DecRef(); m_ptr = new WareType; IncRef(); }
	void CreateInstance( const SharedObjectClass& obj ) {
		if ( m_ptr ) DecRef(); m_ptr = new WareType( obj ); IncRef(); }
	SharewarePtr& operator=( const SharewarePtr& ptr ) {
		if(this == &ptr) return *this; if ( m_ptr ) DecRef(); m_ptr = ptr.m_ptr; IncRef(); return *this; }

public:
	bool operator==( const SharewarePtr& ptr ) const { return m_ptr == ptr.m_ptr; }
	bool operator!=( const SharewarePtr& ptr ) const { return m_ptr != ptr.m_ptr; }
	SharedObjectClass& operator*() { assert( m_ptr ); return m_ptr->SharedObject(); }
	const SharedObjectClass& operator*() const { assert( m_ptr ); return m_ptr->SharedObject(); }
	operator SharedObjectClass*() { assert( m_ptr ); return &m_ptr->SharedObject(); }
	operator const SharedObjectClass* () const { assert( m_ptr ); return &m_ptr->SharedObject(); }
	SharedObjectClass* operator->() { return &m_ptr->SharedObject(); }
	const SharedObjectClass* operator->() const { return &m_ptr->SharedObject(); }

private:
	void IncRef() { assert( m_ptr ); m_ptr->IncRef(); }
	void DecRef() { assert( m_ptr ); m_ptr->DecRef();
		if ( m_ptr->RefCount() == 0 ) {
			delete m_ptr; m_ptr = 0; } }

private:
	WareType* m_ptr;
};

template<class ObjClass>
class IIterator
{
public:
	virtual ~IIterator() {};
public:
	virtual void Start() = 0;
	virtual bool Done() = 0;
	virtual void Step() = 0;
	virtual ObjClass& Get() = 0;
};

template<class ObjClass>
class IDirectionalContainer
{
public:
	virtual ~IDirectionalContainer() {};
public:
	typedef IIterator<ObjClass> IIterator;
	virtual IIterator* NewIterator() = 0;
};

template<class ObjClass>
class IBidirectionalContainer
{
public:
	virtual ~IBidirectionalContainer() {};
public:
	typedef IIterator<ObjClass> IIterator;
	virtual IIterator* NewIterator() = 0;
	virtual IIterator* NewReverseIterator() = 0;
};


template<class ObjectClass>
class UeSmartPtr
{
	class Ref: public SmallObject{
	public:
		Ref():nCount(0){}
		~Ref(){}
		long nCount;
	};

public:
	UeSmartPtr() : m_ptr( 0 ), m_pRef(0) {}
	UeSmartPtr( ObjectClass* obj )
	{ 
		m_pRef = new Ref; 
		m_ptr = obj;
		IncRef();
	}
	UeSmartPtr( const UeSmartPtr& ware ){
		m_ptr = ware.m_ptr;
		m_pRef = ware.m_pRef;
		IncRef();
	}
	~UeSmartPtr() {
		DecRef();
	}

public:
	UeSmartPtr& operator=( ObjectClass* obj ) {
		if(m_pRef != NULL)
		{
			DecRef();
		}
		m_pRef = new Ref;
		m_ptr = obj;
		IncRef();
		return *this;
	}

	UeSmartPtr& operator=( const UeSmartPtr& ptr ) {
		if(this == &ptr)
			return *this;
		
		if ( m_ptr )
			DecRef(); 
		m_ptr = ptr.m_ptr; 
		m_pRef = ptr.m_pRef;
		IncRef(); 
		return *this;
	}

public:
	bool operator==( const UeSmartPtr& ptr ) const { 
		return m_ptr == ptr.m_ptr;
	}

	bool operator==(ObjectClass* pObj) const {
		return m_ptr == pObj;
	}
	
	bool operator!=( const UeSmartPtr& ptr ) const { 
		return m_ptr != ptr.m_ptr;
	}

	bool operator!=( ObjectClass* pObj ) const { 
		return m_ptr != pObj;
	}

	ObjectClass& operator*() { 
		assert( m_ptr );
		return *m_ptr;
	}
	const ObjectClass& operator*() const {
		assert( m_ptr ); 
		return *m_ptr;
	}
	operator ObjectClass*() {
		assert( m_ptr );
		return m_ptr; 
	}
	operator const ObjectClass* () const { 
		assert( m_ptr ); 
		return m_ptr;
	}
	ObjectClass* operator->() {
		return m_ptr;		
	}
	
	const ObjectClass* operator->() const {
		return m_ptr;
	}
	bool IsNull() const {
		return ( m_ptr == NULL );
	}

private:
	void IncRef() { 
		if( m_pRef != NULL)
			InterlockedIncrement(&m_pRef->nCount);
	}
	void DecRef() {
		if(m_pRef == NULL)
			return;

		if (InterlockedDecrement(&m_pRef->nCount) <= 0)
		{
			delete m_ptr;
			delete m_pRef;
			m_ptr = 0;
		}
	}

private:
	ObjectClass* m_ptr;
	Ref* m_pRef;
};
#endif // !defined(AFX_ITERATORCOMMON_H__FBB43028_A5D2_4DA2_9374_1926BC49796C__INCLUDED_)
